<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>货物追踪与运输数据可视化</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
        }
        
        body {
            background: #1a2a6c;
            color: #ecf0f1;
            min-height: 100vh;
            padding: 15px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            padding: 15px 0;
            margin-bottom: 15px;
        }
        
        h1 {
            font-size: 2.2rem;
            margin-bottom: 5px;
            background: linear-gradient(90deg, #3498db, #2ecc71);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        
        .subtitle {
            font-size: 1rem;
            color: #bdc3c7;
        }
        
        .dashboard {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-bottom: 15px;
        }
        
        @media (max-width: 768px) {
            .dashboard {
                grid-template-columns: 1fr;
            }
        }
        
        .map-container, .stats-panel {
            background: rgba(44, 62, 80, 0.8);
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
            height: 400px;
        }
        
        #map {
            height: 100%;
            width: 100%;
        }
        
        .map-overlay {
            position: absolute;
            top: 10px;
            right: 10px;
            background: rgba(0, 0, 0, 0.7);
            padding: 10px;
            border-radius: 8px;
            z-index: 1000;
            max-width: 200px;
        }
        
        .stats-panel {
            padding: 15px;
            display: grid;
            grid-template-columns: 1fr 1fr;
            grid-template-rows: auto 1fr;
            gap: 10px;
        }
        
        .panel-header {
            grid-column: span 2;
            text-align: center;
            padding: 5px 0;
            border-bottom: 1px solid #3498db;
            margin-bottom: 5px;
        }
        
        .stat-card {
            background: rgba(52, 73, 94, 0.6);
            border-radius: 8px;
            padding: 10px;
            text-align: center;
        }
        
        .stat-value {
            font-size: 1.8rem;
            font-weight: bold;
            margin: 10px 0;
            color: #2ecc71;
        }
        
        .stat-label {
            font-size: 0.85rem;
            color: #bdc3c7;
        }
        
        .charts-container {
            display: grid;
            grid-template-columns: 1fr;
            gap: 15px;
            margin-top: 15px;
        }
        
        .chart-card {
            background: rgba(44, 62, 80, 0.8);
            border-radius: 12px;
            padding: 15px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
            height: 300px;
        }
        
        .chart-card h3 {
            margin-bottom: 10px;
            color: #3498db;
            text-align: center;
        }
        
        .controls {
            display: flex;
            justify-content: center;
            flex-wrap: wrap;
            gap: 10px;
            margin: 15px 0;
        }
        
        .control-btn {
            background: #3498db;
            border: none;
            padding: 8px 15px;
            border-radius: 20px;
            color: white;
            cursor: pointer;
            transition: all 0.2s;
        }
        
        .control-btn:hover {
            background: #2980b9;
            transform: translateY(-2px);
        }
        
        .legend {
            display: flex;
            gap: 10px;
            margin-top: 8px;
            flex-wrap: wrap;
            justify-content: center;
        }
        
        .legend-item {
            display: flex;
            align-items: center;
            font-size: 0.8rem;
        }
        
        .legend-color {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            margin-right: 5px;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>货物追踪与运输数据可视化</h1>
            <p class="subtitle">实时位置追踪 & 运输数据分析</p >
        </header>
        
        <div class="dashboard">
            <div class="map-container">
                <div id="map"></div>
                <div class="map-overlay">
                    <h3>实时货物位置</h3>
                    <div class="legend">
                        <div class="legend-item">
                            <div class="legend-color" style="background-color: #3498db;"></div>
                            <span>普通</span>
                        </div>
                        <div class="legend-item">
                            <div class="legend-color" style="background-color: #e74c3c;"></div>
                            <span>加急</span>
                        </div>
                        <div class="legend-item">
                            <div class="legend-color" style="background-color: #f1c40f;"></div>
                            <span>易碎</span>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="stats-panel">
                <div class="panel-header">
                    <h3>运输数据概览</h3>
                </div>
                <div class="stat-card">
                    <div class="stat-value">142</div>
                    <div class="stat-label">今日运单量</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value">96.4%</div>
                    <div class="stat-label">准时率</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value">18.6h</div>
                    <div class="stat-label">平均运输时间</div>
                </div>
                <div class="stat-card">
                    <div class="stat-value">76</div>
                    <div class="stat-label">在途货物</div>
                </div>
            </div>
        </div>
        
        <div class="controls">
            <button class="control-btn" id="realTimeBtn">实时追踪</button>
            <button class="control-btn" id="refreshBtn">刷新数据</button>
            <button class="control-btn" id="toggleHeatBtn">切换热力图</button>
        </div>
        
        <div class="charts-container">
            <div class="chart-card">
                <h3>每日运单量趋势</h3>
                <canvas id="dailyChart"></canvas>
            </div>
        </div>
    </div>

    <script>
        // 初始化地图
        const map = L.map('map').setView([34.0522, -118.2437], 13);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            attribution: '&copy; OpenStreetMap contributors'
        }).addTo(map);
        
        // 货物位置数据
        const cargoData = [
            {id: 'C1001', lat: 34.0522, lng: -118.2437, type: 'normal'},
            {id: 'C1002', lat: 34.0485, lng: -118.2558, type: 'urgent'},
            {id: 'C1003', lat: 34.0469, lng: -118.2341, type: 'fragile'},
            {id: 'C1004', lat: 34.0578, lng: -118.2486, type: 'normal'},
            {id: 'C1005', lat: 34.0431, lng: -118.2563, type: 'urgent'},
            {id: 'C1006', lat: 34.0554, lng: -118.2372, type: 'normal'},
            {id: 'C1007', lat: 34.0498, lng: -118.2465, type: 'fragile'},
            {id: 'C1008', lat: 34.0536, lng: -118.2521, type: 'normal'},
            {id: 'C1009', lat: 34.0505, lng: -118.2397, type: 'urgent'},
            {id: 'C1010', lat: 34.0473, lng: -118.2489, type: 'normal'}
        ];
        
        // 货物图标
        const cargoIcons = {
            normal: L.divIcon({
                html: '<div style="background-color: #3498db; width: 16px; height: 16px; border-radius: 50%; border: 2px solid white; box-shadow: 0 0 5px rgba(0,0,0,0.5);"></div>',
                className: '',
                iconSize: [20, 20]
            }),
            urgent: L.divIcon({
                html: '<div style="background-color: #e74c3c; width: 16px; height: 16px; border-radius: 50%; border: 2px solid white; box-shadow: 0 0 5px rgba(0,0,0,0.5);"></div>',
                className: '',
                iconSize: [20, 20]
            }),
            fragile: L.divIcon({
                html: '<div style="background-color: #f1c40f; width: 16px; height: 16px; border-radius: 50%; border: 2px solid white; box-shadow: 0 0 5px rgba(0,0,0,0.5);"></div>',
                className: '',
                iconSize: [20, 20]
            })
        };
        
        // 添加货物标记
        const markers = [];
        cargoData.forEach(cargo => {
            const marker = L.marker([cargo.lat, cargo.lng], {icon: cargoIcons[cargo.type]})
                .addTo(map)
                .bindPopup(`<b>${cargo.id}</b><br>类型: ${cargo.type === 'normal' ? '普通' : cargo.type === 'urgent' ? '加急' : '易碎'}`);
            markers.push(marker);
        });
        
        // 初始化折线图
        const dailyCtx = document.getElementById('dailyChart').getContext('2d');
        const dailyChart = new Chart(dailyCtx, {
            type: 'line',
            data: {
                labels: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
                datasets: [{
                    label: '运单量',
                    data: [120, 135, 142, 156, 178, 92, 105],
                    borderColor: '#3498db',
                    backgroundColor: 'rgba(52, 152, 219, 0.1)',
                    borderWidth: 2,
                    tension: 0.3,
                    fill: true
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        labels: {
                            color: '#ecf0f1'
                        }
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true,
                        grid: {
                            color: 'rgba(255, 255, 255, 0.1)'
                        },
                        ticks: {
                            color: '#bdc3c7'
                        }
                    },
                    x: {
                        grid: {
                            color: 'rgba(255, 255, 255, 0.1)'
                        },
                        ticks: {
                            color: '#bdc3c7'
                        }
                    }
                }
            }
        });
        
        // 模拟实时更新
        function updatePositions() {
            cargoData.forEach((cargo, index) => {
                // 随机移动货物位置
                const latChange = (Math.random() - 0.5) * 0.002;
                const lngChange = (Math.random() - 0.5) * 0.002;
                
                cargo.lat += latChange;
                cargo.lng += lngChange;
                
                markers[index].setLatLng([cargo.lat, cargo.lng]);
            });
            
            // 更新统计数据
            document.querySelectorAll('.stat-card .stat-value')[0].textContent = 
                Math.floor(142 + Math.random() * 10);
        }
        
        // 每3秒更新一次位置
        setInterval(updatePositions, 3000);
        
        // 按钮事件
        document.getElementById('refreshBtn').addEventListener('click', function() {
            updatePositions();
            alert('数据已刷新！');
        });
        
        document.getElementById('realTimeBtn').addEventListener('click', function() {
            alert('实时追踪模式已激活');
        });
        
        document.getElementById('toggleHeatBtn').addEventListener('click', function() {
            alert('热力图功能需要完整版实现');
        });
        
        // 初始加载时聚焦到货物
        setTimeout(() => {
            const bounds = L.latLngBounds(cargoData.map(cargo => [cargo.lat, cargo.lng]));
            map.fitBounds(bounds, {padding: [30, 30]});
        }, 500);
    </script>
</body>
</html>